import backtrader as bt
from collections import deque
from .DbOprate import DbOprate

class HighBreakoutStrategy(bt.Strategy):
    """
    G1:=40;
    G2:=20;
    X_10:=CLOSE=HHV(CLOSE,G1);
    X_11:=BARSLAST(FILTER(CROSS(0.8,X_10),G2))+1;
    GD:=REF(HIGH,X_11);
    F1:=O>GD AND C>GD AND C>O;
    DA:=BARSLAST(F1);
    GD2:=REF(GD,DA);
    F2:F1 AND GD2!=REF(GD2,1);
    """
    params = (
        ('g1', 40),      # G1:=40
        ('g2', 20),      # G2:=20
    )

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print(f'{dt.isoformat()}, {txt}')

    def __init__(self):
        self.data_close = self.datas[0].close
        self.data_open = self.datas[0].open  
        self.data_high = self.datas[0].high

        # X_10:=CLOSE=HHV(CLOSE,G1)
        self.hhv_close = bt.indicators.Highest(self.data_close, period=self.p.g1)
        self.x_10 = (self.data_close == self.hhv_close)
        
        # 记录FILTER信号发生的位置
        self.filter_signal_bars = []  # 存储有效的FILTER信号bar位置
        self.f2_history = []          # 存储历史F2信号信息，用于GD2!=REF(GD2,1)比较
        
        # 用于调试的变量
        self.debug_mode = False

    def next(self):
        if len(self) < self.p.g1:
            return
            
        current_bar = len(self)
        current_date = self.datas[0].datetime.date(0)
        current_close = self.data_close[0]
        current_open = self.data_open[0]
        current_high = self.data_high[0]

        # 获取X_10当前和前一个值
        x_10_curr = bool(self.x_10[0]) if not (hasattr(self.x_10[0], 'isnan') and self.x_10[0].isnan()) else False
        x_10_prev = False
        if len(self.x_10) >= 2:
            x_10_prev = bool(self.x_10[-1]) if not (hasattr(self.x_10[-1], 'isnan') and self.x_10[-1].isnan()) else False

        # CROSS(0.8, X_10) = X_10从1变为0
        cross_signal = x_10_prev and not x_10_curr
        
        if self.debug_mode:
            print(f'{current_date}, X_10={x_10_curr}, CROSS={cross_signal}')

        # 处理CROSS信号并应用FILTER逻辑
        if cross_signal:
            # 检查是否满足FILTER条件（G2周期内只允许一次）
            can_filter = True
            if self.filter_signal_bars:
                last_filter_bar = self.filter_signal_bars[-1]
                if (current_bar - last_filter_bar) < self.p.g2:
                    can_filter = False
            
            if can_filter:
                self.filter_signal_bars.append(current_bar)
                if self.debug_mode:
                    print(f'  *** FILTER信号 *** BAR={current_bar}, DATE={current_date}')

        # 只有在有FILTER信号的情况下才继续后续判断
        if not self.filter_signal_bars:
            return

        # 计算X_11 = BARSLAST(FILTER) + 1
        last_filter_bar = self.filter_signal_bars[-1]
        x_11 = current_bar - last_filter_bar + 1
        
        if self.debug_mode:
            print(f'  X_11 = {x_11}')

        # 计算GD = REF(HIGH, X_11)
        try:
            gd = self.data_high[-x_11]
        except IndexError:
            gd = current_high  # 如果索引越界，使用当前最高价作为fallback
            
        if self.debug_mode:
            print(f'  GD = {gd:.2f}')

        # F1:=O>GD AND C>GD AND C>O
        f1 = (current_open > gd) and (current_close > gd) and (current_close > current_open)
        
        if self.debug_mode:
            print(f'  F1 = {f1}, O={current_open:.2f}, C={current_close:.2f}, GD={gd:.2f}')

        # 只有当F1条件满足时才检查F2
        if f1:
            # DA:=BARSLAST(F1) - 当前就是F1，所以DA=0
            da = 0
            
            # GD2:=REF(GD,DA) = REF(GD,0) = 当前GD值
            gd2 = gd
            
            # REF(GD2,1) - 前一个GD2值
            ref_gd2 = None
            if self.f2_history:
                # 获取上一次F2信号时的GD值
                ref_gd2 = self.f2_history[-1]['gd']
            
            # F2:F1 AND GD2!=REF(GD2,1)
            # 如果是第一次F2信号，ref_gd2为None，则默认触发
            f2 = ref_gd2 is None or gd2 != ref_gd2
            
            if self.debug_mode:
                print(f'  GD2 = {gd2:.2f}, REF(GD2,1) = {ref_gd2}, F2 = {f2}')

            if f2:
                # 记录F2信号信息
                f2_info = {
                    'bar': current_bar,
                    'date': current_date.isoformat(),
                    'x_11': x_11,
                    'gd': gd2,
                    'f1_valid': True,
                    'f2_valid': True
                }
                self.f2_history.append(f2_info)
                
                if self.debug_mode:
                    print(f'  *** F2信号触发 *** {current_date}')
                    print('  ' + '='*50)
                
                # 保存买入信号点到数据库
                try:
                    result = {
                        'strategy': 'HighBreakoutStrategy',
                        'stock_code': self.datas[0]._name,
                        'op_act': 'buy_signal',  # 标记为买点信号
                        'op_price': float(current_close),
                        'op_num': 100,  # 默认数量，可以根据需要调整
                        'op_comm': 0.0,
                        'op_dt': current_date.isoformat(),
                        'reason': 'F2_SIGNAL_TRIGGER',
                        'can_use_money': float(max(0, self.broker.getcash())),
                        'init_cash': float(self.broker.startingcash),
                        'stock_num': int(max(0, self.position.size)),
                        'stock_amount': float(max(0, self.position.size * current_close)),
                        'profitable': 0.0
                    }
                    DbOprate.save_result_to_mysql(result)
                    if self.debug_mode:
                        print(f'  *** 买入信号已存入数据库 *** 价格: {current_close:.2f}')
                except Exception as e:
                    if self.debug_mode:
                        print(f'  *** 数据库存储失败 *** 错误: {str(e)}')

    def notify_order(self, order):
        pass

    def notify_trade(self, trade):
        pass

    def stop(self):
        # 策略结束时可以做一些清理工作
        if self.debug_mode:
            print(f'策略执行完成，共检测到 {len(self.f2_history)} 个F2信号')
